/***************************************************************************
 *   Copyright (c) 2004 Jürgen Riegel <juergen.riegel@web.de>              *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/


#ifndef APPLICATION_H
#define APPLICATION_H
#include <boost_signals2.hpp>
#include <map>
#include <string>
#include <QtGui/QPixmap>
#define  putpix()

// #include "../GUI/Document.h"
// #include "App/Application.h"
// #include "boost/signals2/preprocessed_signal.hpp"
class QCloseEvent;
class SoNode;
namespace Base{
class Type;
class FileInfo;
class FileInfoList;
}
namespace App{
class Document;
class Property;
class PropertyContainer;
    class DocumentObject;
}
namespace Gui{
class BaseView;
class CommandManager;
class Document;
class MDIView;

class MenuItem;
class PreferencePackManager;
class ViewProvider;
class ViewProviderDocumentObject;

/** The Application main class
 * This is the central class of the GUI
 * @author Jürgen Riegel, Werner Mayer
 */
class  Application
{
public:
    /// construction
    Application(bool GUIenabled);
    /// destruction
    ~Application();

    /** @name methods for support of files */
    //@{
    /// open a file
    void open(const char* FileName, const char* Module);
    /// import a file into the document DocName
    void importFrom(const char* FileName, const char* DocName, const char* Module);
    /// Export objects from the document DocName to a single file
    void exportTo(const char* FileName, const char* DocName, const char* Module);
    /// Reload a partial opened document
    App::Document *reopen(App::Document *doc);
    //@}
    void set_widgets(QWidget* qw);
    QWidget* main_widget;


    /** @name methods for View handling */
    //@{
    /// send Messages to the active view
    bool sendMsgToActiveView(const char* pMsg, const char** ppReturn=nullptr);
    /// send Messages test to the active view
    bool sendHasMsgToActiveView(const char* pMsg);
    /// send Messages to the focused view
    bool sendMsgToFocusView(const char* pMsg, const char** ppReturn=nullptr);
    /// send Messages test to the focused view
    bool sendHasMsgToFocusView(const char* pMsg);
    /// Attach a view (get called by the FCView constructor)
    void attachView(Gui::BaseView* pcView);
    /// Detach a view (get called by the FCView destructor)
    void detachView(Gui::BaseView* pcView);
    /// get called if a view gets activated, this manage the whole activation scheme
    void viewActivated(Gui::MDIView* pcView);
    /// call update to all documents and all views (costly!)
    void onUpdate();
    /// call update to all views of the active document
    void updateActive();
    /// call update to all command actions
    void updateActions(bool delay = false);
    //@}

    /** @name Signals of the Application */
    //@{
    /// signal on new Document
    boost::signals2::signal<void (const Gui::Document&, bool)> signalNewDocument;
    /// signal on deleted Document
    boost::signals2::signal<void (const Gui::Document&)> signalDeleteDocument;
    /// signal on relabeling Document
    boost::signals2::signal<void (const Gui::Document&)> signalRelabelDocument;
    /// signal on renaming Document
    boost::signals2::signal<void (const Gui::Document&)> signalRenameDocument;
    /// signal on activating Document
    boost::signals2::signal<void (const Gui::Document&)> signalActiveDocument;
    /// signal on new Object
    boost::signals2::signal<void (const Gui::ViewProvider&)> signalNewObject;
    /// signal on deleted Object
    boost::signals2::signal<void (const Gui::ViewProvider&)> signalDeletedObject;

    /// signal on changed Object
    boost::signals2::signal<void (const Gui::ViewProvider&, const App::Property&)> signalBeforeChangeObject;
    /// signal on changed object property
    boost::signals2::signal<void (const Gui::ViewProvider&, const App::Property&)> signalChangedObject;
    /// signal on renamed Object
    boost::signals2::signal<void (const Gui::ViewProvider&)> signalRelabelObject;
    /// signal on activated Object
    boost::signals2::signal<void (const Gui::ViewProvider&)> signalActivatedObject;
    /// signal on activated workbench
    boost::signals2::signal<void (const char*)> signalActivateWorkbench;
    /// signal on added workbench
    boost::signals2::signal<void (const char*)> signalAddWorkbench;
    /// signal on removed workbench
    boost::signals2::signal<void (const char*)> signalRemoveWorkbench;
    /// signal on show hidden items
    boost::signals2::signal<void (const Gui::Document&)> signalShowHidden;
    /// signal on activating view
    boost::signals2::signal<void (const Gui::MDIView*)> signalActivateView;
    /// signal on entering in edit mode
    boost::signals2::signal<void (const Gui::ViewProviderDocumentObject&)> signalInEdit;
    /// signal on leaving edit mode
    boost::signals2::signal<void (const Gui::ViewProviderDocumentObject&)> signalResetEdit;
    /// signal on changing user edit mode
    boost::signals2::signal<void (int)> signalUserEditModeChanged;
    //@}

    /** @name methods for Document handling */
    //@{
protected:
    /// Observer message from the Application
    void slotNewDocument(const App::Document&,bool);
    void slotDeleteDocument(const App::Document&);
    void slotRelabelDocument(const App::Document&);
    void slotRenameDocument(const App::Document&);
    void slotActiveDocument(const App::Document&);
    void slotShowHidden(const App::Document&);
    void slotNewObject(const ViewProvider&);
    void slotDeletedObject(const ViewProvider&);
    
    void slotChangedObject(const ViewProvider&, const App::Property& Prop);
    void slotRelabelObject(const ViewProvider&);
    void slotActivatedObject(const ViewProvider&);
    void slotInEdit(const Gui::ViewProviderDocumentObject&);
    void slotResetEdit(const Gui::ViewProviderDocumentObject&);

public:
    /// message when a GuiDocument is about to vanish
    void onLastWindowClosed(Gui::Document* pcDoc);
    /// Getter for the active document
    Gui::Document* activeDocument() const;
    /// Set the active document
    void setActiveDocument(Gui::Document* pcDocument);
    /// Getter for the editing document
    Gui::Document* editDocument() const;
    Gui::MDIView* editViewOfNode(SoNode *node) const;
    /// Set editing document, which will reset editing of all other document
    void setEditDocument(Gui::Document* pcDocument);
    /** Retrieves a pointer to the Gui::Document whose App::Document has the name \a name.
    * If no such document exists 0 is returned.
    */
    Gui::Document* getDocument(const char* name) const;
    /** Retrieves a pointer to the Gui::Document whose App::Document matches to \a pDoc.
    * If no such document exists 0 is returned.
    */
    Gui::Document* getDocument(const App::Document* pDoc) const;
    /// Getter for the active view of the active document or null
    Gui::MDIView* activeView() const;
    /// Activate a view of the given type of the active document
    void activateView(const Base::Type&, bool create=false);
    /// Shows the associated view provider of the given object
    void showViewProvider(const App::DocumentObject*);
    /// Hides the associated view provider of the given object
    void hideViewProvider(const App::DocumentObject*);
    /// Get the view provider of the given object
    Gui::ViewProvider* getViewProvider(const App::DocumentObject*) const;
    //@}

    /// true when the application shutting down
    bool isClosing();
    void checkForPreviousCrashes();

    /** @name workbench handling */
    //@{
    /// Activate a named workbench
    bool activateWorkbench(const char* name);
    QPixmap workbenchIcon(const QString&) const;
    QString workbenchToolTip(const QString&) const;
    QString workbenchMenuText(const QString&) const;
    QStringList workbenches() const;
    void setupContextMenu(const char* recipient, MenuItem*) const;
    //@}

    /** @name Appearance */
    //@{
    /// Activate a named workbench
    void setStyleSheet(const QString& qssFile, bool tiledBackground);
    //@}

    /** @name User Commands */
    //@{
    /// Get macro manager
    /// Reference to the command manager
    Gui::CommandManager &commandManager();
    /// helper which create the commands
    void createStandardOperations();
    //@}

    Gui::PreferencePackManager* prefPackManager();
    void set_action(int id);
    void new_sketch();

    /** @name Init, Destruct an Access methods */
    //@{
    /// some kind of singleton
    static Application* Instance;
    static void initApplication();
    static void initTypes();
    static void initOpenInventor();
    static void runInitGuiScript();
    static void runApplication();
    void tryClose( QCloseEvent * e );
    //@}
    
    /** @name User edit mode */
    //@{
protected:
    // the below std::map is a translation of 'EditMode' enum in ViewProvider.h
    // to add a new edit mode, it should first be added there

    const std::map <int, std::string> userEditModes {
        {0, QT_TRANSLATE_NOOP("EditMode", "Default")},
        {1, QT_TRANSLATE_NOOP("EditMode", "Transform")},
        {2, QT_TRANSLATE_NOOP("EditMode", "Cutting")},
        {3, QT_TRANSLATE_NOOP("EditMode", "Color")}
    };
    int userEditMode = userEditModes.begin()->first;

public:
    std::map <int, std::string> listUserEditModes() const { return userEditModes; }
    int getUserEditMode(const std::string &mode = "") const;
    std::string getUserEditModeName(int mode = -1) const;
    bool setUserEditMode(int mode);
    bool setUserEditMode(const std::string &mode);
    //@}

public:

private:
    struct ApplicationP* d;

};

} //namespace Gui

#endif
